#-*- coding: utf-8 -*-
"""
Calculatrice améliorée (basée sur un squelette donné par le prof)
Par Guillaume HUYSMANS (2013).
"""
from polynomial import Polynomial

class pyPol(object):
    """ pyPol:
           Petite calculatrice permettant de 
           manipuler des polynômes.
    """
    def __init__(self):
        self.version = '1.0'
        self.features = ['add, substract, multiply and divide',
                        'differentiate',
                        'evaluate']
        self.vars = {}
        s1 = 'Welcome in pyPol ' + self.version + ' - Polynomials Calculator'
        s2 = 'Mainly made by You!'
        blanks = ' ' * ((len(s1) - len(s2)) / 2)
        print s1 + '\n' + blanks + s2 + blanks
        print '\n' + 'Type \'help\' to know how to use pyPol'
        print 'Type \'bye\', \'exit\' or \'quit\' to quit pyPol'
        print 'Type \'vars\', \'clvars\' to display/clear variables'
    
    def run(self):
        input = raw_input('pyPol> ').strip()
        if input == 'quit' or \
           input == 'exit' or \
           input == 'bye':
            return False
        elif input == 'help':
            self.displayHelp()
            return True
        elif input == 'vars':
            self.displayVars()
            return True
        elif input == 'clvars':
            self.clearVars()
            return True
        if input[:6] == 'print ':
            input = input[6:]
        try: 
            res = self.parse(input)
            print res
        except ValueError as e:
            print 'Sorry but I cannot parse \'' + input + '\': %s' % str(e)
            print 'Type \'help\' if lost.'
        return True

    def getPolynomial(self, s):
        if s in self.vars:
            return self.vars[s]
        else:
            return Polynomial(s)

    def parse(self, input):
        #TODO gérer la priorité des opérations... là c'est un peu du n'importe quoi
        ##print "DEBUG:", input
        if input.find('=') != -1:
            sep = input.find('=')
            name = input[:sep].strip()
            data = self.parse(input[sep+1:])
            if ' ' in name:
                raise ValueError('Invalid variable name!')
            elif '[' in name:
                pos = name.find('[')
                idx = int(name[pos+1:-1])
                name = name[:pos] #le vrai !
                self.vars[name][idx] = data[0]
                if len(data)>1:
                    print "Warning: variable x was discarded during assignment."
                return data[0]
            else:
                self.vars[name] = data
                return data
        elif input.find(')\'') != -1: #dérivée (je prends la fin pour ne pas confondre)
            index = input.find(')\'')
            a = self.parse(input[1:index]).deriv()
            return self.parse(str(a)+input[index+2:])
        elif input.find('(') != -1: #évaluation
            index = input.find('(')
            a = self.parse(input[0:index])
            x = input[index+1:-1]
            return a.eval(Polynomial.conv(x))
        elif input.find('+') != -1:
            index = input.find('+')
            a = self.parse(input[:index])
            b = self.parse(input[index+1:])
            return a + b
        elif input.find('*') != -1:
            index = input.find('*')
            a = self.parse(input[:index])
            b = self.parse(input[index+1:])
            return a * b
        elif input.find('/') != -1:
            index = input.find('/')
            a = self.parse(input[:index])
            b = self.parse(input[index+1:])
            ret = a/b
            if isinstance(ret, tuple):
                return str(ret[0])+' [reste '+str(ret[1])+']'
            else:
                return ret
        else:
            #on ne reconnait rien, ça doit être un simple polynome
            return self.getPolynomial(input.strip())

    def displayVars(self):
        for v in self.vars:
            print v+'='+str(self.vars[v])

    def clearVars(self):
        self.vars.clear()
            
    def displayHelp(self):
        line = ('-' * 26) + ' pyPol ' + self.version + ' ' + ('-' * 26)
        print line
        print 'In version ' + self.version + ', pyPol can :'
        for f in self.features:
            print '* '+f
        print line
        print 'Examples of inputs:'
        print '   x^3+7x+9 + x^7+12x^3+x+5'
        print '   x^2+x+1 * 4x+4'
        print '   (x^5+3x^7)\''
        print '   x^2'
        print line
        print 'List of commands:'
        print '   quit/exit/bye: exit pyPol'
        print '   help: display this help'

if __name__ == '__main__':
    calculette = pyPol()
    while calculette.run():
        pass
